#include <iostream>
#include <stdio.h>
#include <strings.h>
#include <fstream>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
#include<sys/types.h>
#include<sys/wait.h>
#include "Log.hpp"

using namespace std;
volatile bool quitSer = false;

#define CRLF "\r\n"
#define CRLF_LEN strlen(CRLF)
#define SPACE " "
#define SPACE_LEN strlen(SPACE)
#define ROOT_PATH "wwwzckx"
#define HOME_PAGE "index.html"

void Usage(void *vgs)
{
    std::cout << "Usage:./tcpserver port ip" << std::endl;
}

string getPath(string in)
{
    size_t pos = in.find(CRLF);
    string request = in.substr(0, pos);
    cout << "request:" << request << endl;
    // get path http/1.0
    size_t first = request.find(SPACE);
    cout << "first:" << first << endl;
    if(first == string:: npos) return nullptr;
    size_t second = request.rfind(SPACE);
    cout << "second:" << second << endl;

    if(second == string::npos) return nullptr;
    string path = request.substr(first + SPACE_LEN, second- (first + SPACE_LEN));
    if(path.size() == 1 && path[0] == '/') path += HOME_PAGE;
    cout << "getPath:" << path << endl;

    return path;
}
string readFile(string& recource)
{
    ifstream in(recource);
    if(!in.is_open()) return "404";
    string content;
    string line;
    while(getline(in, line)) content += line;
    return content;
}

void Serverhttp(int sock)
{
    char buffer[10240];
    ssize_t s = read(sock, buffer, sizeof buffer);
    cout << s << endl;
    if(s > 0)
    {
        logMessage(DEBUG, "read success..");
        std::cout << buffer;
    }
    // // // string response = "HTTP/1.1 301 Permanent redirect\r\n";   //临时重定向
    // // // response +="Location: https://blog.csdn.net/qq_59456417?spm=1011.2415.3001.5343r\n";
    // // // response += "\r\n";
    // // // send(sock, response.c_str(), response.size(), 0);

    // 1. 获取路径
    string path = getPath(buffer);

    string recource = ROOT_PATH;
    recource += path;
    cout << recource << endl;
    
    string html = readFile(recource);

    // 开始响应
    string response;
    response = "HTTP/1.0 200 OK\r\n";
    response += "Content-Type:text/html\r\n";
    response += ("Content-Length:" + std::to_string(html.size()) + "\r\n");
    response += "Set-Cookie: this is my Cookie content\r\n";
    response += "\r\n";
    //response += "<html><h1>hello world!!</h1><html>\r\n";
    response += html;

    send(sock, response.c_str(), response.size(), 0);
}

class server
{
public:
    server(int port, std::string ip = "")
        : sockfd_(-1), ip_(ip), port_(port)
    {
    }
    ~server()
    {
    }

public:
    void init()
    {
        // 1. 创建套接字
        sockfd_ = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd_ < 0)
        {
            logMessage(FATAL, "socket:%s[%d]", strerror(errno), sockfd_);
            exit(SOCK_ERR);
        }
        logMessage(DEBUG, "socket success..");

        // 2.填充域
        struct sockaddr_in local;
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(port_);
        ip_.empty() ? (local.sin_addr.s_addr = INADDR_ANY) : (inet_aton(ip_.c_str(), &local.sin_addr));

        // 3. 绑定网络信息
        if (bind(sockfd_, (const struct sockaddr *)&local, sizeof(local)) < 0)
        {
            logMessage(FATAL, "bind:%s[%d]", strerror(errno), sockfd_);
            exit(BIND_ERR);
        }
        logMessage(DEBUG, "bind success...");

        // 4. 监听套接字
        if (listen(sockfd_, 5) < 0)
        {
            logMessage(FATAL, "listen:%s[%d]", strerror(errno), sockfd_);
            exit(LISTEN_ERR);
        }
        logMessage(DEBUG, "listen success...");

        // 完成
    }

    void start()
    {
        char inbuffer_[1024]; // 用来接收客户端发来的消息
        // 提供服务
        while (true)
        {
            quitSer = false;
            
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            // 5. 获取连接, accept 的返回值是一个新的socket fd
            logMessage(DEBUG,"start1");
            int serviceSock = accept(sockfd_, (struct sockaddr *)&peer, &len);
            logMessage(DEBUG,"start2");
            if (serviceSock < 0)
            {
                // 获取链接失败
                logMessage(WARINING, "accept: %s[%d]", strerror(errno), serviceSock);
                continue;
            }
            logMessage(DEBUG, "accept success");

            pid_t id = fork();
            if(id == 0)
            {
                pid_t tid = fork();
                if(tid == 0)
                {
                    uint16_t peerPort = htons(peer.sin_port);
                    std::string peerIp = inet_ntoa(peer.sin_addr);
                    Serverhttp(serviceSock);
                    exit(0);
                }

                exit(0);
            }
            close(serviceSock);
            int ret = waitpid(id, nullptr, 0);
            if(ret < 0)
            {
                logMessage(WARINING, "wait child error:%d", errno);
            }
            logMessage(DEBUG, "wait success...");
        }
    }

private:
    int sockfd_;
    uint16_t port_;
    std::string ip_;
};

// ./tcpserver port ip
int main(int argc, char *argv[])
{
    if (argc < 2 || argc > 3)
    {
        Usage(argv[0]);
        exit(USAGE_ERR);
    }

    uint16_t port = atoi(argv[1]);
    std::string ip;
    if (argc == 3)
        ip = argv[2];
    std::cout << port << ":" << ip << std::endl; 

    server tcpSer(port, ip);
    tcpSer.init();
    tcpSer.start();
    return 0;
}
